package com.gopay.bis.citic.micro.operation;

import java.io.UnsupportedEncodingException;
import java.security.SignatureException;
import java.util.Map;
import java.util.TreeMap;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.net.URLDecoder;
import java.util.List;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.builder.ToStringBuilder;

import com.gopay.common.exception.GopayException;
import com.gopay.remote.bank.ICertHelperThirdParty;



/** 
 * 小额免密支付工具类
 * @ClassName: MicroPatCerHelper 
 * @author w_jiqing 
 * @date 2017年5月24日 下午3:27:50  
 */ 
public class MicroPatCerHelper implements ICertHelperThirdParty{

    private  String key;
    /**
     * 加密方法
     * 
     */
    public String sign(Object requestMsg) throws GopayException{
        Map<String, String> map =xmlToMap((String)requestMsg);
        Map<String,String> params=SignUtils.paraFilter(map);
        StringBuilder buf = new StringBuilder((params.size() +1) * 10);
        SignUtils.buildPayParams(buf,params,false);
        String preStr = buf.toString();
        String sign = (MD5.sign(preStr, "&key="+key, "utf-8")).toUpperCase();
        map.put("sign", sign);
        return XmlBeanUtil.parseXML(map);        
    }
    public String sign(Object requestMsg,String privateKey) throws GopayException{
        Map<String, String> map =xmlToMap((String)requestMsg);
        Map<String,String> params=SignUtils.paraFilter(map);
        StringBuilder buf = new StringBuilder((params.size() +1) * 10);
        SignUtils.buildPayParams(buf,params,false);
        String preStr = buf.toString();
        String sign = (MD5.sign(preStr, "&key="+privateKey, "utf-8")).toUpperCase();
        map.put("sign", sign);
        return XmlBeanUtil.parseXML(map);        
    }
    
    /**
     * 验签方法
     */
    @Override
    public Object verify(Object responseMsg) throws GopayException {
        try {
            Map<String,String> map = XmlBeanUtil.toMap(((String)responseMsg).getBytes(), "utf-8");
            if(map.containsKey("sign")){
                if(SignUtils.checkParam(map, key)){
                    return true;
                }
            }else{
                return false;
            }
        } catch (Exception e) {            
            throw new  GopayException("验签失败",e);
        }
        return false;    
    }

    public Object verify(Object responseMsg,String privateKey) throws GopayException {
        try {
            Map<String,String> map = XmlBeanUtil.toMap(((String)responseMsg).getBytes(), "utf-8");
            if(map.containsKey("sign")){
                if(SignUtils.checkParam(map, privateKey)){
                    return true;
                }
            }else{
                return false;
            }
        } catch (Exception e) {            
            e.printStackTrace();
            throw new  GopayException("验签失败",e);
        }
        return false;    
    }
    /** 
     * @Description: 判断是否通信成功
     * @param responseMsg
     * @return
     * @throws GopayException 
     * @author w_jiqing 
     */
    public boolean isSuccessStatus(Object responseMsg)throws GopayException{
        try {
            Map<String,String> map = XmlBeanUtil.toMap(((String)responseMsg).getBytes(), "utf-8");
            if("0".equals(map.get("status"))){
                return true;
            }
        } catch (Exception e) {
            throw new  GopayException("验签失败",e);
        }
        return false;
        
    }
   
    public static boolean checkParam(Map<String,String> params,String key){
        boolean result = false;
        if(params.containsKey("sign")){
            String sign = params.get("sign");
            params.remove("sign");
            StringBuilder buf = new StringBuilder((params.size() +1) * 10);
            SignUtils.buildPayParams(buf,params,false);
            String preStr = buf.toString();
            String signRecieve = sign(preStr, "&key=" + key, "utf-8");
            result = sign.equalsIgnoreCase(signRecieve);
        }
        return result;
    }
    
    public static String sign(String text, String key, String input_charset) {
        text = text + key;
        return DigestUtils.md5Hex(getContentBytes(text, input_charset));
    }
    /**
     * @param content
     * @param charset
     * @return
     * @throws SignatureException
     * @throws UnsupportedEncodingException 
     */
    private static byte[] getContentBytes(String content, String charset) {
        if (charset == null || "".equals(charset)) {
            return content.getBytes();
        }
        try {
            return content.getBytes(charset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("charset not support exception:" + charset);
        }
    }

    
    @SuppressWarnings("unchecked")
    public static Map<String, String> xmlToMap(String xmlStr)
    {        
        SAXBuilder builder = new SAXBuilder();
        Map<String, String> map = new TreeMap<String, String>();
        try {
            xmlStr = URLDecoder.decode(xmlStr, "UTF-8");
            Reader in = new StringReader(xmlStr);
            Document doc = builder.build(in);
            Element root = doc.getRootElement();
            List<Element> list = root.getChildren();
            for (Element e : list) 
                map.put(e.getName(), e.getText());
            return map;
        } catch (JDOMException e) {
        } catch (UnsupportedEncodingException e) {
        } catch (IOException e) {
        } catch (Exception e) {
        }
        
        return map;        
    }
    
    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }

    public static void main(String[] args) {
        String aa = "<xml><service>unified.trade.micropay</service><version>2.0</version><charset>UTF-8</charset><sign_type>MD5</sign_type>"
    +"<mch_id>7551000001</mch_id><nonce_str>cT1zhVGPsLHrLXg8rNzv</nonce_str><sign></sign><groupno></groupno><out_trade_no>16121703662412</out_trade_no>"
  +"<device_info></device_info><body>测试</body><attach></attach><total_fee>1</total_fee></xml>";
        
        String bb= "<xml><service>unified.trade.refund</service><version>2.0</version><charset>UTF-8</charset><sign_type>MD5</sign_type><mch_id>7551000001</mch_id>"
  +"<nonce_str>CRkR6EDXinZkwfDIgdZY</nonce_str><sign></sign><out_trade_no>16121703662412</out_trade_no><transaction_id></transaction_id><out_refund_no>TK16121703662412</out_refund_no>"
  +"<total_fee>1</total_fee><refund_fee>1</refund_fee><op_user_id>7551000001</op_user_id><refund_channel>ORIGINAL</refund_channel></xml>";
        Map<String, String> map =xmlToMap(bb);
        System.out.println(map);
    }
    
}
